﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gfw.Infrastructure.Account;
using Gfw.Infrastructure.ExceptionImpl;
using Gfw.Infrastructure.User;
using Gfw.Models.Account;
using Gfw.Models.User;
using Gfw.Repositories.Account;
using Gfw.Repositories.Admin;
using Gfw.Repository;

namespace Gfw.Infrastructure.Facilities
{
    /// <summary>
    /// 提现，包括申请提现
    /// </summary>
    public class CashFacility : IFacility
    {
        #region Const Fields

        private const decimal CommissionRate = 0.1M; // 提现手续费 10%

        #endregion

        #region Private Fields

        string _userID, _bankName, _bankCardNo, _bankUserName, _checkerID, _bankSerialNo, _tradeAbstract;
        long _count; // 申请提现金额
        DateTime _applyDate; // 申请时间

        #endregion

        #region 申请提现(for 会员)

        /// <summary>
        /// 初始化
        /// <para>for 会员</para>
        /// </summary>
        /// <param name="userID">申请人ID</param>
        /// <param name="count">申请金额</param>
        /// <param name="bankCardNo">账号</param>
        /// <param name="bankName">开户行（四大银行 + 财付通 + 支付宝）字典</param>
        /// <param name="bankUserName">开户名</param>
        public CashFacility(string userID, long count, string bankName, string bankCardNo,
            string bankUserName)
        {
            if (string.IsNullOrEmpty(userID))
                throw new GfwVerifyException("用户ID错误！");

            if (count <= 0)
                throw new GfwVerifyException("金额不正确！");

            if (string.IsNullOrWhiteSpace(bankName) || string.IsNullOrWhiteSpace(bankCardNo) ||
                string.IsNullOrWhiteSpace(bankUserName))
                throw new GfwVerifyException("银行信息不完整！");

            this._userID = userID;
            this._count = count;
            this._bankName = bankName;
            this._bankCardNo = bankCardNo;
            this._bankUserName = bankUserName;
        }

        /// <summary>
        /// 申请操作
        /// <para>for 会员</para>
        /// </summary>
        /// <param name="unitOfWork"></param>
        public void ExecuteApply(Repository.UnitOfWork unitOfWork = null)
        {
            try
            {
                if (unitOfWork != null)
                    throw new GfwException("当前事务只能作为原子事务，不允许与其它操作公用数据库事务。");

                UnitOfWork work = unitOfWork ?? new UnitOfWork();

                ActUserAccountinformationRepository accountRep = new ActUserAccountinformationRepository(); // 修改：用户账户信息表
                ActUserBargain4cashRepository userCashRep = new ActUserBargain4cashRepository(); // 修改：用户现金币交易明细
                ActCompanyCashRepository comCashRep = new ActCompanyCashRepository(); // 修改：公司(用户)提现记录表

                var userAccount = accountRep.Get(this._userID, work);
                if (userAccount == null)
                    throw new GfwVerifyException("申请用户不存在！");
                if (userAccount.Cash < _count)
                    throw new GfwVerifyException("余额不足！");

                userAccount.Cash -= this._count;
                DateTime applyDate = DateTime.Now;
                ActUserBargain4cash userCashHistory = new ActUserBargain4cash()
                {
                    Id = Guid.NewGuid().ToString(),
                    Userid = this._userID,
                    TradeType = (int)UserTradeTypeEnum.ToCash,
                    Income = 0,
                    Outlay = this._count,
                    Balance = userAccount.Cash,
                    TradeDate = applyDate,
                    TradeAbstract = "审核中",
                    AwardSerialNo = "",
                };

                ActCompanyCash comCash = new ActCompanyCash()
                {
                    Id = Guid.NewGuid().ToString(),
                    Userid = this._userID,
                    BankName = this._bankName,
                    BankCardNo = this._bankCardNo,
                    BankUserName = this._bankUserName,
                    Money = this._count,
                    RequireDate = applyDate,
                    Status = (int)CashStatusEnum.Wait,
                    BankSerialNo = string.Empty,
                };


                accountRep.Update(userAccount, work);
                userCashRep.Save(userCashHistory, work);
                comCashRep.Save(comCash, work);

                if (unitOfWork == null)
                    work.Commit();
            }
            catch (System.Exception ex)
            {
                throw new GfwVerifyException(ex.Message);
            }
        }

        #endregion

        #region 提现操作(for 管理员)

        /// <summary>
        /// 初始化
        /// <para>for 管理员</para>
        /// </summary>
        /// <param name="userID">用户ID</param>
        /// <param name="applyDate">申请日期</param>
        /// <param name="count">申请金额</param>
        /// <param name="checkerID">审核客服ID</param>
        /// <param name="bankSerialNo">银行流水号</param>
        /// <param name="tradeAbstract">摘要</param>
        public CashFacility(string userID, DateTime applyDate, long count, 
            string checkerID, string bankSerialNo, string tradeAbstract)
        {
            if (string.IsNullOrEmpty(userID))
                throw new GfwVerifyException("用户ID错误！");

            this._userID = userID;
            this._applyDate = applyDate;
            this._count = count;
            this._checkerID = checkerID;
            this._bankSerialNo = bankSerialNo;
            this._tradeAbstract = tradeAbstract;
        }

        /// <summary>
        /// 允许提现（收取手续费）
        /// <para>for 管理员</para>
        /// </summary>
        /// <param name="unitOfWork"></param>
        public void Execute(Repository.UnitOfWork unitOfWork = null)
        {
            try
            {
                if (unitOfWork != null)
                    throw new GfwException("当前事务只能作为原子事务，不允许与其它操作公用数据库事务。");

                UnitOfWork work = unitOfWork ?? new UnitOfWork();
                ActCompanyCashRepository comCashRep = new ActCompanyCashRepository(); // 修改：公司(用户)提现记录表
                ActUserBargain4cashRepository userCashRep = new ActUserBargain4cashRepository(); // 修改：用户现金币交易明细
                /* Modify by: Fan 2012-08-08
                 * 由于并发的原因，公司账户在每晚进行结算。
                ActCompanyAccountinformationRepository comAccountRep = new ActCompanyAccountinformationRepository(); // 修改：公司帐户信息表
                 */
                ActCompanyBargainRepository bargainRep = new ActCompanyBargainRepository(); // 修改：公司帐户交易明细

                var comCash = comCashRep.GetCashByUserIDAndApplyDate(this._userID, this._applyDate, work);
                if (comCash == null)
                    throw new GfwVerifyException("没有查询到该用户的申请信息！");

                if (comCash.Status != 0) // 不为“审核中”状态，表示已经审核过了！
                    throw new GfwVerifyException("该用户已经审核过了，不能再次审核！");

                var userCash = userCashRep.GetUserCashBargainByUserIDAndTradeDate(this._userID, this._applyDate, work);
                if (userCash == null)
                    throw new GfwVerifyException("没有查询到该用户的X币交易信息！");

                DateTime tradeDate = DateTime.Now;

                comCash.Checkerid = this._checkerID;
                comCash.BankSerialNo = this._bankSerialNo;
                comCash.TradeAbstract = this._tradeAbstract;
                comCash.CheckDate = tradeDate;
                comCash.Status = (int)CashStatusEnum.Pass;
                comCash.Taxation = comCash.Money * CommissionRate;
                comCash.TaxationSerialNo = Guid.NewGuid().ToString();


                userCash.TradeAbstract = "审核通过！" + this._tradeAbstract;

                /*
                var comAccount = comAccountRep.GetAll(work).FirstOrDefault();
                if (comAccount == null)
                {
                    comAccount = new ActCompanyAccountinformation()
                    {
                        Id = Guid.NewGuid().ToString(),
                        SettlementDate = tradeDate,
                    };

                    comAccountRep.Save(comAccount, work);
                }

                comAccount.Profit = comAccount.Profit - this._count + comCash.Taxation;
                comAccount.SettlementDate = tradeDate;
                 */


                ActCompanyBargain comBargainOut = new ActCompanyBargain() // 支出（提现）
                {
                    Id = Guid.NewGuid().ToString(),
                    Userid = this._userID,
                    TradeType = (int)CompanyTradeTypeEnum.ToCash,
                    Income = 0,
                    Outlay = this._count,
                    /*
                    Balance = comAccount.Profit - comCash.Taxation,
                     */
                    Balance = 0,
                    TradeDate = tradeDate,
                    TradeAbstract = "兑换  " + this._tradeAbstract,
                    AwardSerialNo = "",
                    TaxationSerialNo = "",
                };

                ActCompanyBargain comBargainIn = new ActCompanyBargain() // 收入（手续费）
                {
                    Id = Guid.NewGuid().ToString(),
                    Userid = this._userID,
                    TradeType = (int)CompanyTradeTypeEnum.ToCashTax,
                    Income = comCash.Taxation,
                    Outlay = 0,
                    /*
                    Balance = comAccount.Profit,
                     */
                    Balance = 0,
                    TradeDate = tradeDate,
                    TradeAbstract = "兑换手续费",
                    AwardSerialNo = "",
                    TaxationSerialNo = comCash.TaxationSerialNo,
                };


                comCashRep.Update(comCash, work);
                userCashRep.Update(userCash, work);
                /*
                comAccountRep.Update(comAccount, work);
                 */
                bargainRep.Save(comBargainOut, work);
                bargainRep.Save(comBargainIn, work);


                if (unitOfWork == null)
                    work.Commit();
            }
            catch (System.Exception ex)
            {
                throw new GfwVerifyException(ex.Message);
            }
        }

        /// <summary>
        /// 不允许提现（说明原因，返还用户预提的金额）
        /// <para>for 管理员</para>
        /// </summary>
        /// <param name="unitOfWork"></param>
        public void ExecuteCancel(Repository.UnitOfWork unitOfWork = null)
        {
            try
            {
                if (unitOfWork != null)
                    throw new GfwException("当前事务只能作为原子事务，不允许与其它操作公用数据库事务。");

                UnitOfWork work = unitOfWork ?? new UnitOfWork();

                ActCompanyCashRepository comCashRep = new ActCompanyCashRepository(); // 修改：公司(用户)提现记录表
                ActUserAccountinformationRepository accountRep = new ActUserAccountinformationRepository(); // 修改：用户账户信息表
                ActUserBargain4cashRepository userCashRep = new ActUserBargain4cashRepository(); // 修改：用户现金币交易明细

                var userAccount = accountRep.Get(this._userID, work);
                if (userAccount == null)
                    throw new GfwVerifyException("申请用户不存在！");

                var comCash = comCashRep.GetCashByUserIDAndApplyDate(this._userID, this._applyDate, work);
                if (comCash == null)
                    throw new GfwVerifyException("没有查询到该用户的申请信息！");

                if (comCash.Status != 0) // 不为“审核中”状态，表示已经审核过了！
                    throw new GfwVerifyException("该用户已经审核过了，不能再次审核！");

                var userCash = userCashRep.GetUserCashBargainByUserIDAndTradeDate(this._userID, this._applyDate, work);
                if (userCash == null)
                    throw new GfwVerifyException("没有查询到该用户的X币交易信息！");

                DateTime tradeDate = DateTime.Now;

                comCash.Checkerid = this._checkerID;
                comCash.BankSerialNo = "";
                comCash.TradeAbstract = this._tradeAbstract;
                comCash.CheckDate = tradeDate;
                comCash.Status = (int)CashStatusEnum.Cancel;
                comCash.Taxation = 0;
                comCash.TaxationSerialNo = "";


                userAccount.Cash += this._count;


                userCash.TradeAbstract = "审核不通过！" + this._tradeAbstract;


                ActUserBargain4cash userReturnCash= new ActUserBargain4cash()
                {
                    Id = Guid.NewGuid().ToString(),
                    Userid = this._userID,
                    TradeType = (int)UserTradeTypeEnum.ToCash,
                    Income = this._count,
                    Outlay = 0,
                    Balance = userAccount.Cash,
                    TradeDate = tradeDate,
                    TradeAbstract = "审核不通过，返还用户金额：" + this._count,
                    AwardSerialNo = "",
                };


                comCashRep.Update(comCash, work);
                accountRep.Update(userAccount, work);
                userCashRep.Update(userCash, work);
                userCashRep.Save(userReturnCash, work);


                if (unitOfWork == null)
                    work.Commit();
            }
            catch (System.Exception ex)
            {
                throw new GfwVerifyException(ex.Message);
            }
        }

        #endregion

    }
}
